using System;
using System.Collections;
using System.Linq;
using System.Reflection;
using UnityEngine;

namespace NodeCanvas.Variables
{
	[Serializable]
	public abstract class BBVariable
	{
		[SerializeField]
		[HideInInspector]
		private Blackboard _bb;

		[SerializeField]
		private string _dataName;

		[SerializeField]
		[HideInInspector]
		private VariableData _dataRef;

		[SerializeField]
		private bool _useBlackboard;

		[SerializeField]
		[HideInInspector]
		private bool _blackboardOnly;

		[SerializeField]
		[HideInInspector]
		private bool _isDynamic;

		private MethodInfo _getMethod;

		private MethodInfo _setMethod;

		private Blackboard overrideBB
		{
			get
			{
				if (string.IsNullOrEmpty(dataName) || !dataName.Contains("/"))
				{
					return null;
				}
				string key = dataName.Substring(0, dataName.IndexOf("/"));
				if (Blackboard.allBlackboards.ContainsKey(key))
				{
					return Blackboard.allBlackboards[key];
				}
				return null;
			}
		}

		private VariableData dataRef
		{
			get
			{
				return _dataRef;
			}
			set
			{
				_dataRef = value;
			}
		}

		public Blackboard bb
		{
			get
			{
				return _bb;
			}
			set
			{
				if (_bb != value)
				{
					_bb = value;
					dataRef = null;
				}
			}
		}

		public bool isDynamic
		{
			get
			{
				return _isDynamic;
			}
			set
			{
				_isDynamic = value;
			}
		}

		public string dataName
		{
			get
			{
				if (dataRef != null)
				{
					if (!string.IsNullOrEmpty(_dataName) && _dataName.Contains("/"))
					{
						return _dataName.Substring(0, _dataName.IndexOf("/") + 1) + dataRef.dataName;
					}
					return dataRef.dataName;
				}
				return _dataName;
			}
			set
			{
				if (!(_dataName != value))
				{
					return;
				}
				_dataName = value;
				if (!string.IsNullOrEmpty(value))
				{
					useBlackboard = true;
					if ((bool)overrideBB)
					{
						dataRef = overrideBB.GetData(_dataName.Substring(_dataName.LastIndexOf("/") + 1), varType);
					}
					else if ((bool)bb)
					{
						dataRef = bb.GetData(_dataName, varType);
					}
				}
				else
				{
					dataRef = null;
				}
			}
		}

		public bool blackboardOnly
		{
			get
			{
				return _blackboardOnly;
			}
			set
			{
				_blackboardOnly = value;
				if (value)
				{
					useBlackboard = true;
				}
			}
		}

		public bool useBlackboard
		{
			get
			{
				return _useBlackboard;
			}
			set
			{
				_useBlackboard = value;
				if (!value)
				{
					dataName = null;
				}
			}
		}

		public bool isNone
		{
			get
			{
				return useBlackboard && string.IsNullOrEmpty(dataName);
			}
		}

		public virtual bool isNull
		{
			get
			{
				return objectValue == null || objectValue.Equals(null);
			}
		}

		public virtual Type varType
		{
			get
			{
				if (_getMethod == null)
				{
					_getMethod = GetType().NCGetMethod("get_value");
				}
				return _getMethod.ReturnType;
			}
		}

		public object objectValue
		{
			get
			{
				if (_getMethod == null)
				{
					_getMethod = GetType().NCGetMethod("get_value");
				}
				return _getMethod.Invoke(this, null);
			}
			set
			{
				if (_setMethod == null)
				{
					_setMethod = GetType().NCGetMethod("set_value");
				}
				_setMethod.Invoke(this, new object[1] { value });
			}
		}

		private object value { get; set; }

		public static void SetBBFields(Blackboard bb, object o)
		{
			InitBBFields(o);
			FieldInfo[] array = o.GetType().NCGetFields();
			foreach (FieldInfo fieldInfo in array)
			{
				if (typeof(IList).NCIsAssignableFrom(fieldInfo.FieldType) && !fieldInfo.FieldType.IsArray)
				{
					IList list = fieldInfo.GetValue(o) as IList;
					if (list == null)
					{
						continue;
					}
					if (typeof(BBVariable).NCIsAssignableFrom(fieldInfo.FieldType.NCGetGenericArguments()[0]))
					{
						foreach (BBVariable item in list)
						{
							item.bb = bb;
						}
					}
				}
				if (typeof(BBVariable).NCIsAssignableFrom(fieldInfo.FieldType))
				{
					(fieldInfo.GetValue(o) as BBVariable).bb = bb;
				}
				if (typeof(BBVariableSet) == fieldInfo.FieldType)
				{
					(fieldInfo.GetValue(o) as BBVariableSet).bb = bb;
				}
			}
		}

		public static void InitBBFields(object o)
		{
			FieldInfo[] array = o.GetType().NCGetFields();
			foreach (FieldInfo fieldInfo in array)
			{
				if (typeof(BBVariable).NCIsAssignableFrom(fieldInfo.FieldType))
				{
					if (fieldInfo.GetValue(o) == null)
					{
						fieldInfo.SetValue(o, Activator.CreateInstance(fieldInfo.FieldType));
					}
					if (fieldInfo.GetCustomAttributes(typeof(BlackboardOnlyAttribute), true).FirstOrDefault() != null)
					{
						(fieldInfo.GetValue(o) as BBVariable).blackboardOnly = true;
					}
				}
				if (typeof(IMultiCastable).NCIsAssignableFrom(fieldInfo.FieldType))
				{
					VariableType variableType = fieldInfo.GetCustomAttributes(typeof(VariableType), true).FirstOrDefault() as VariableType;
					if (variableType != null)
					{
						(fieldInfo.GetValue(o) as IMultiCastable).type = variableType.type;
					}
				}
			}
		}

		public override string ToString()
		{
			UnityEngine.Object @object = ((!typeof(UnityEngine.Object).NCIsAssignableFrom(varType)) ? null : ((UnityEngine.Object)objectValue));
			return "'<b>" + (useBlackboard ? ("$" + dataName) : (isNull ? "NULL" : ((!@object) ? objectValue.ToString() : @object.name))) + "</b>'";
		}

		protected T Read<T>()
		{
			if (dataRef != null)
			{
				if (dataRef.objectValue == null || dataRef.objectValue.Equals(null))
				{
					return default(T);
				}
				return (T)dataRef.objectValue;
			}
			if (overrideBB != null)
			{
				dataRef = overrideBB.GetData(dataName.Substring(dataName.LastIndexOf("/") + 1), typeof(T));
				return overrideBB.GetDataValue<T>(dataName.Substring(dataName.LastIndexOf("/") + 1));
			}
			if (bb != null)
			{
				dataRef = bb.GetData(dataName, typeof(T));
				return bb.GetDataValue<T>(dataName);
			}
			return default(T);
		}

		protected void Write(object o)
		{
			if (dataRef != null)
			{
				dataRef.objectValue = o;
			}
			else if (overrideBB != null)
			{
				dataRef = overrideBB.SetDataValue(dataName.Substring(dataName.LastIndexOf("/") + 1), o);
			}
			else if (bb != null)
			{
				dataRef = bb.SetDataValue(dataName, o);
			}
			else
			{
				Debug.LogError("BBVariable has neither linked VariableData, nor blackboard");
			}
		}
	}
	[Serializable]
	public abstract class BBVariable<T> : BBVariable
	{
		[SerializeField]
		protected T _value;

		public T value
		{
			get
			{
				return (!base.useBlackboard) ? _value : Read<T>();
			}
			set
			{
				if (base.useBlackboard)
				{
					Write(value);
				}
				else
				{
					_value = value;
				}
			}
		}
	}
}
